# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-2007 Renato Chencarek <renato.chencarek@gmail.com>
# All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# Author: Renato Chencarek <renato.chencarek@gmail.com>
# Contributing author: Peter-Henry Mander <phmander@gmail.com>

from trac.wiki.macros import WikiMacroBase
from trac.util.html import Markup, html, escape

from tempfile import *
from urllib import *
import re, os

class TexPdfView(WikiMacroBase):
    '''
    This is the Tex version of PdfView macro.
    '''
    def render_macro(self, req, name, content):
#        # returning a local filename works
#        result = "\\includegraphics{/export/home/x86_64/Work/Data/httpd-2.2.3/htdocs/apache_pb.png}"
#        return result
        try:
            # args will be null if the macro is called without parenthesis.
            if not content:
                error_msg = "\\begin{verbatim}\nERROR!\n[[%s]]\nNo arguments. At least file name expected.\n\\end{verbatim}" % (name)
                return error_msg
            # parse arguments
            # we expect the 1st argument to be a filename (filespec)
            args = content.split(',')

            if len(args) == 0:
                error_msg = "\\begin{verbatim}\nERROR!\n[[%s(%s)]]\nNo arguments. At least file name expected.\n\\end{verbatim}" % (name, content)
                return error_msg
                #raise Exception("No argument.")

            result = ''
            filespec = args[0]
            size_re = re.compile('[0-9]+%?$')
            attr_re = re.compile('(align|border|width|height|alt|texwidth|texheight'
                                 '|title|longdesc|class|id|usemap)=(.+)')
            quoted_re = re.compile("(?:[\"'])(.*)(?:[\"'])$")
            attr = {}
            style = {}
            nolink = False
            for arg in args[1:]:
                arg = arg.strip()
                if size_re.match(arg):
                    # 'width' keyword
                    attr['width'] = arg
                    continue
                if arg == 'nolink':
                    nolink = True
                    continue
                if arg in ('left', 'right', 'top', 'bottom'):
                    style['float'] = arg
                    continue
                match = attr_re.match(arg)
                if match:
                    key, val = match.groups()
                    m = quoted_re.search(val) # unquote "..." and '...'
                    if m:
                        val = m.group(1)
                    if key == 'align':
                        style['float'] = val
                        attr['align'] = val
                    elif key == 'border':
                        style['border'] = '%dpt' % int(val);
                    elif key == 'width' or key == 'height':
                        attr[str(key)] = '%dpt' % int(val);
                    else:
                        attr[str(key)] = val # will be used as a __call__ keyword

            # parse filespec argument to get module and id if contained.
            parts = filespec.split(':')
            url = None
            if len(parts) == 3:                 # module:id:attachment
                module, id, file = parts
                #result = "%s\\begin{verbatim}\nDEBUG!\nmodule=%s\nid=%s\nfile=%s\n\\end{verbatim}\n" % (result, module, id, file)
                if module not in ['wiki', 'ticket']:
                    error_msg = "\\begin{verbatim}\nERROR:\nmodule=%s cannot have attachments\n\\end{verbatim}" % parts[0]
                    return error_msg
            elif len(parts) == 2:
                schema, resource = parts
                if schema == 'http' or schema == 'ftp':
                    # pmander BUGBUG try the simplest first!
                    raw_url = url = desc = filespec
                elif schema == 'https':
                    debug = "\\begin{verbatim}\nWARN! resource is encrypted with https\nschema=%s\nresource=%s\n\\end{verbatim}" % (schema, resource)
                    return debug #############################
                else:
                    # source: or other schema supported by trac
                    from trac.versioncontrol.web_ui import BrowserModule
                    try:
                        browser_links = [link for link,_ in
                                         BrowserModule(self.env).get_link_resolvers()]
                    except Exception:
                        browser_links = []
                    if parts[0] in browser_links:   # source:path
                        module, file = parts
                        rev = None
                        if '@' in file:
                            file, rev = file.split('@')
                        url = req.href.browser(file, rev=rev)
                        raw_url = req.href.browser(file, rev=rev, format='raw')
                        desc = filespec
                    else: # #ticket:attachment or WikiPage:attachment
                        # FIXME: do something generic about shorthand forms...
                        id, file = parts
                        if id and id[0] == '#':
                            module = 'ticket'
                            id = id[1:]
                        elif id == 'htdocs':
                            raw_url = url = req.href.chrome('site', file)
                            desc = os.path.basename(file)
                        elif id in ('http', 'https', 'ftp'): # external URLs
                            raw_url = url = desc = id+':'+file
                        else:
                            module = 'wiki'
            elif len(parts) == 1:               # attachment
                # determine current object
                # FIXME: should be retrieved from the formatter...
                # ...and the formatter should be provided to the macro
                file = parts[0]
                module, id = 'wiki', 'WikiStart'
                path_info = req.path_info.split('/',2)
                if len(path_info) > 1:
                    module = path_info[1]
                if len(path_info) > 2:
                    id = path_info[2]
                if module not in ['wiki', 'ticket']:
                    error_msg = "\\begin{verbatim}\nERROR!\nCannot reference local attachment from here\nfile=%s\n\\end{verbatim}\n" % (file)
                    return error_msg
                #result = "%s\\begin{verbatim}\nDEBUG!\nmodule=%s\nid=%s\nfile=%s\n\\end{verbatim}\n" % (result,module,id,file)
            else:
                error_msg = "\\begin{verbatim}\nERROR!\n[[%s???]]\nNo filespec parsed.\n\\end{verbatim}\n" % (name, content)
                return error_msg

            if style:
                attr['style'] = '; '.join(['%s:%s' % (k, escape(v))
                                           for k, v in style.iteritems()])

            tex_attr= ""
            #tex_attr = "[width=0.4\\textwidth]" # works , 40% of text width
            # tex_attr = "[width=60mm,height=60mm]" # works, may not preserve aspect ratio
            # tex_attr = "[width=60mm]" # width alone works, preserves aspect ratio
            if url:
                tmp_file = self.save_file(self.env.tempdir, url, "http://" + req.server_name + ":" + str(req.server_port))
                #result = "%s\\begin{verbatim}\nDEBUG!\n[[%s(%s)]]\ntmp_file=%s\n\\end{verbatim}\n" %(result,name,content,tmp_file)
                result = "%s" % (result)
                result = "%s\\includegraphics%s{%s}\n" % (result,tex_attr, tmp_file)
                #result = self.parse_tex_args(tmp_file,args,style)
                return result
            else: # this is an attachment
                from trac.attachment import Attachment
                attachment = Attachment(self.env, module, id, file)
                url = attachment.href(req)
                trac_base_url = self.env.config.get('trac','base_url')
                schema,path = trac_base_url.split(req.server_name)
                junk,file_path = url.split(path)
                # The following assumes that the trac.ini file contains the correct project_root_dir entry
                root_dir = self.env.config.get('trac', 'project_root_dir')
                absolute_path = root_dir + file_path.replace('/attachment/','/attachments/',1)
                #result = "%s\\begin{verbatim}\nDEBUG!\nurl=%s\n\\end{verbatim}\n" %(result,url)
                result = "%s\\includegraphics%s{%s}\n" %(result,tex_attr,absolute_path)
                #result = self.parse_tex_args(absolute_path,args,style)
                return result

            return result

        except Exception, e:
            print "EXCEPTION", e

    def parse_tex_args(self, url, args, style):
        keys = args.keys()
        if "border" in style.keys():
            border = style["border"]
        else:
            border = False

        if "title" in keys:
            caption = args["title"]
        else:
            caption = None

        if "texwidth" in keys:
            width = args["texwidth"]
        else:
            width = 0

        if "texheight" in keys:
            height = args["texheight"]
        else:
            height = 0

        if "id" in keys:
            label = args["id"]
        else:
            label = None

        if "align" in keys:
            align = args["align"]
        else:
            align = None

        base = ""
        if width and height:
            base = "\\includegraphics[width=%s,height=%s]{%s}" % (width, height, url)
        else:
            if width:
                base = "\\includegraphics[width=%s]{%s}" % (width, url)
            elif height:
                base = "\\includegraphics[height=%s]{%s}" % (height, url)
            else:
                base = "\\includegraphics{%s}" % url

        if border:
            base  = "\\setlength{\\fboxrule}{%s}\n\\fbox{%s}" % (border, base)

        if align:
            if align == "center":
                base = "\\begin{center}\n%s\n\\end{center}" % base
            elif align == "left":
                base = "\\begin{flushleft}\n%s\n\\end{flushleft}" % base
            elif align == "right":
                base = "\\begin{flushright}\n%s\n\\end{flushright}" % base

        if label or caption:
            if caption:
                base = "%s\n\\caption{%s}" % (base, caption)

            if label:
                base = "%s\n\\label{%s}" % (base, label)

            base = "\\begin{figure}[htbp]\n%s\n\\end{figure}" % base

        return base

    #
    # dir_path: temporary storage path
    #      url: source URL of image
    #   server: default server, if host not included in URL
    #
    def save_file(self, dir_path, url, server):
        host, path = splithost(url)
        basename, ext = os.path.splitext(os.path.basename(path))
        dirname = os.path.dirname(path)

        if not host:
            host = server

        fd, name = mkstemp(dir = dir_path, suffix = basename)
        os.unlink(name)

        found = False
        if ext not in [".pdf", ".epdf"]:
            for new_ext in [".pdf", ".epdf"]:
                new_url = basejoin(host, dirname + "/" + basename + new_ext + "?format=raw")
                output, headers = urlretrieve(new_url, name + new_ext)
                if not headers or "pdf" not in str(headers.gettype()):
                    continue
                else:
                    found = True
                    ext = new_ext
                    break
        if not found:
            new_url = basejoin(host, dirname + "/" + basename + ext + "?format=raw")
            urlretrieve(new_url, name + ext)

        return name + ext
